/*
 * StringTemplateServletSupport.java
 *
 * Copyright 2011 Jack Leow
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package my.edu.clhs.stringtemplate.servlet;

import org.antlr.stringtemplate.CommonGroupLoader;
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import org.antlr.stringtemplate.language.DefaultTemplateLexer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.InitialContext;
import javax.naming.NameNotFoundException;

/**
 * Utility class for working with StringTemplate in a Servlet environment.
 *
 * @author Jack Leow
 * @version 1.0
 * @since 1.0 (Jan 11, 2011, 10:33 PM)
 */
public final class StringTemplateSupport {
    public static final String DEVELOPMENT_MODE_FLAG_NAME =
        "my.edu.clhs.stringtemplate.DEVELOPMENT_MODE";
    private static final Logger log =
        LoggerFactory.getLogger(StringTemplateSupport.class);
    private static final StringTemplateGroup servletUtilTemplateGroup =
        new CommonGroupLoader("my/edu/clhs/stringtemplate/servlet", null).
        loadGroup("servlet-util", DefaultTemplateLexer.class, null);
    final boolean developmentMode;
    
    public StringTemplateSupport() {
        if (Boolean.getBoolean(DEVELOPMENT_MODE_FLAG_NAME)) {
            developmentMode = true;
        } else {
            Boolean devModeFlagInDir = null;
            
            try {
                InitialContext ctx = new InitialContext();
                devModeFlagInDir = (Boolean)ctx.lookup(
                    "java:comp/env/" + DEVELOPMENT_MODE_FLAG_NAME);
            } catch (NameNotFoundException e) {
                // This is the preferred set up.
                log.debug(DEVELOPMENT_MODE_FLAG_NAME +
                    " not in directory - defaulting to non-development mode");
            } catch (Throwable t) {
                log.warn("error accessing directory - " +
                    "defaulting to non-development mode", t);
            }
            
            developmentMode = devModeFlagInDir != null &&
                devModeFlagInDir.booleanValue();
        }
        
        if (developmentMode) {
            log.warn("StringTemplate files are being loaded in development " +
                "mode, which may not be optimal in production environments");
        }
    }
    
    /**
     * Appends the "servlet-util"
     * (my.edu.clhs.stringtemplate.servlet.servlet-util.stg) StringTemplateGroup
     * as the top-most (lower precedent) super group of the given
     * {@link org.antlr.stringtemplate.StringTemplateGroup} hierarchy.
     *
     * @param templateGroup the StringTemplateGroup hierarchy to append to
     */
    public void appendServletUtilTemplateGroup(
            StringTemplateGroup templateGroup) {
        log.debug("entering " +
            "appendServletUtilTemplateGroup(StringTemplateGroup)");
        StringTemplateGroup superGroup = templateGroup.getSuperGroup();
        StringTemplateGroup topGroup = templateGroup;
        
        while (superGroup != null &&
                !servletUtilTemplateGroup.equals(superGroup)) {
            topGroup = superGroup;
            superGroup = superGroup.getSuperGroup();
        }
        if (!servletUtilTemplateGroup.equals(superGroup)) {
            topGroup.setSuperGroup(servletUtilTemplateGroup);
        }
        log.debug("exiting " +
            "appendServletUtilTemplateGroup(StringTemplateGroup)");
    }
    
    void prepareTemplateLoader(
            StringTemplateGroup templateLoader) {
        if (developmentMode) {
            templateLoader.setRefreshInterval(0);
        }
    }
    
    /**
     * Loads the template with the specified template name, through the given
     * StringTemplateGroup.
     *
     * @param templateName the name of the template to load
     * @param templateLoader the StringTemplateGroup to load the template with
     * @return the template with the specified name;
     *  or <tt>null</tt> if there is no such template
     */
    public StringTemplate loadViewTemplate(
            String templateName, StringTemplateGroup templateLoader) {
        log.debug("entering loadViewTemplate(String,StringTemplateGroup)");
        StringTemplate template = null;
        
        prepareTemplateLoader(templateLoader);
        try {
            template = templateLoader.getInstanceOf(templateName);
            template.setGroup(templateLoader);
        } catch (IllegalArgumentException e) {
            if (!e.getMessage().startsWith("Can't find template")) {
                throw e;
            }
            log.info("template \"" + templateName + "\" not found");
        }
        
        log.debug("exiting loadViewTemplate(String,StringTemplateGroup)");
        return template;
    }
    
    /**
     * Loads the layout template, using the templateName to resolve the content
     * template group through the given StringTemplateGroup.
     *
     * <p>Note that this method loads templates as {@link org.antlr.stringtemplate.StringTemplateGroup}
     * using {@link org.antlr.stringtemplate.StringTemplateGroup#loadGroup(String)}, which can (and
     * probably should) be customized using a custom
     * {@link org.antlr.stringtemplate.StringTemplateGroupLoader}.
     *
     * @param templateGroupName the name of the template group to load
     * @param layoutTemplatePath the path to the layout template
     * @param templateLoader the StringTemplateGroup to load the template with
     * @return the template with the specified name;
     *  or <tt>null</tt> if there is no such template
     */
    public StringTemplate loadLayoutTemplate(
            String templateGroupName, String layoutTemplatePath,
            StringTemplateGroup templateLoader) {
        log.debug("entering" +
            "loadLayoutTemplate(String,String,StringTemplateGroup)");
        StringTemplate layout = null;
        
        prepareTemplateLoader(templateLoader);
        StringTemplateGroup group =
            StringTemplateGroup.loadGroup(templateGroupName);
        
        if (group != null) {
            layout = templateLoader.getInstanceOf(
                templateLoader.getTemplateNameFromFileName(
                layoutTemplatePath));
            layout.setGroup(group);
        }
        
        log.debug("exiting" +
            "loadLayoutTemplate(String,String,StringTemplateGroup)");
        return layout;
    }
}